﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TV_Organizer;
using System.Collections.ObjectModel;
using System.Windows;
using System.ComponentModel.Composition;
using Ionic.Zip;

using io = System.IO;
using System.Threading.Tasks;

namespace BetaSeriesConnector
{
    [TVSubtitlesConnector("BetaSeries")]
    [TVShowsConnector("BetaSeries")]
    public class BetaSeriesConnector : ITVSubtitlesConnector, ITVShowsConnector<BSShow>
    {
        public BetaSeriesConnector()
        {
            this.Initialize();
        }

        #region props

        private ObservableCollection<BSShow> _shows = new ObservableCollection<BSShow>();
        public IEnumerable<BSShow> Shows { get { return _shows; } }

        #endregion

        private void Initialize()
        {
            if (!io.File.Exists(Constants.CacheFile))
            {
                string responseString = TV_Organizer.Helpers.WebHelpers.GetStringFromUrl(Constants.AllShowsURL);
                var response = responseString.DeserializeXML<BSResponse>();

                if (response != null)
                {
                    _shows.AddRange(response.Shows);
                    response.LogErrors(this, "Initialize cache");
                }
            }
            else
            {
                var cacheContent = io.File.ReadAllText(Constants.CacheFile);
                var cachedShows = cacheContent.DeserializeXML<BSShow[]>();
                if (cachedShows != null)
                    _shows.AddRange(cachedShows);
            }

            Application.Current.Dispatcher.BeginInvoke(new System.Action(() =>
            {
                Application.Current.Exit += new ExitEventHandler(OnApplicationExit);
            }));
        }

        private void OnApplicationExit(object sender, ExitEventArgs e)
        {
            var serializedValue = _shows.SerializeToXML();
            if (!string.IsNullOrEmpty(serializedValue))
                System.IO.File.WriteAllText(Constants.CacheFile, serializedValue);
        }

        #region SUBTITLES CONNECTOR

        public Task<IEnumerable<TV_Organizer.Subtitles.Subtitle>> SearchSubtitlesForAsync(TVShow tvShow, TV_Organizer.Episode episode)
        {
            return Task.Factory.StartNew<IEnumerable<TV_Organizer.Subtitles.Subtitle>>(() =>
            {
                var result = new Collection<TV_Organizer.Subtitles.Subtitle>();
                if (!(tvShow is BSShow) || episode == null) return result;

                var url = Constants.GetSubtitlesURL(((BSShow)tvShow).Url, episode.Season, episode.EpisodeNumber, Constants.SubtitleLanguage.VOVF);
                string responseString = TV_Organizer.Helpers.WebHelpers.GetStringFromUrl(url);
                var response = responseString.DeserializeXML<BSResponse>();
                if (response == null) return result;

                response.LogErrors(this, string.Format("Search subtitles for {0}", episode));
                if (response.Subtitles == null) return result;

                foreach (var subsCollection in response.Subtitles)
                {
                    foreach (var sub in subsCollection.ToSubtitles())
                    {
                        int season, episodeNumber;
                        File.GetSeasonAndEpisode(sub.Filename, out season, out episodeNumber);

                        if (season == episode.Season && episodeNumber == episode.EpisodeNumber)
                            result.Add(sub);
                    }
                }

                return result;
            });
        }

        public async Task<bool> DownloadSubtitleAsync(TV_Organizer.Subtitles.Subtitle subtitle, string filename)
        {
            var sub = subtitle as BSSubtitle;
            if (sub == null) return false;

            var task = TV_Organizer.Helpers.WebHelpers.SaveUrlToTempFileAsync(sub.Url);
            await task;

            var zip = ZipFile.Read(task.Result);
            var entry = zip.Entries.FirstOrDefault(e => e.FileName == sub.Filename);
            if (entry == null) return false;

            await TaskEx.Run(() =>
            {
                using (var fStream = new io.FileStream(filename, io.FileMode.Create))
                {
                    entry.Extract(fStream);
                }
            });

            return true;
        }

        #endregion

        #region SHOWS CONNECTOR

        public IEnumerable<BSShow> SearchShow(string search)
        {
            var shows = this.Shows.Where(s =>
                s.Name.ToLowerInvariant().ReplaceChars(TV_Organizer.FileScanner.Constants.CleanupCharacters, TV_Organizer.FileScanner.Constants.CleanupCharactersReplacement)
                .Contains(search.ToLowerInvariant()));

            return shows.ToList();
        }

        public Episode GetEpisode(TVShow show, int season, int episode)
        {
            var bsShow = show as BSShow;
            if (bsShow == null) return null;

            var xml = TV_Organizer.Helpers.WebHelpers.GetStringFromUrl(Constants.GetEpisodeURL(bsShow.Url, season, episode));
            var response = xml.DeserializeXML<BSResponse>();
            response.LogErrors(this, string.Format("Fetching episode S{0}E{1} for {2}", show.Name, season.ToString("d2"), episode.ToString("d2")));

            if (response.Seasons == null) return null;
            var bsSeason = response.Seasons.FirstOrDefault(s => s.SeasonNumber == season);
            if (bsSeason == null) return null;

            return bsSeason.GetEpisode(episode);
        }

        #endregion

    }
}
